/*
 * MonteCarloForm.java
 *
 * Created on 7 de Julho de 2011, 16:32
 */

package intopo.demonstrator.partnerselection.gui;

import intopo.demonstrator.partnerselection.State;
import java.awt.Color;
import java.util.Timer;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.event.DocumentEvent;

/**
 * Main form of the <i>partner selection</i> model.  Provides components to edit the parameters of the model, components that show data about the current state of the Markov Chain.
 * There are also statistics, the raw data and plots from the current run of the Markov Chain.  The user can run model step by step or run it until it reacheas an absorbing state.
 * @author  Pedro Mariano
 */
public class MonteCarloForm
	extends javax.swing.JFrame
{
	final private MarkovChainHistoryTableModel history;

	/**
	 * The current timer.  When the user presses the <i>run</i> button a new timer is instanciated.
	 */
	private Timer timer;
	/**
	 * An array that provides an indexed acess to the textfields that show the transition probabilities.
	 */
	transient private JTextField[] transitionTextField;
	/**
	 * An array that provides an indexed access to the buttons that perform specific transitions of the Markov Chain.
	 */
	transient private JButton[] transitionButton;
	/**
	 * Creates new form MonteCarloForm
	 */
	public MonteCarloForm ()
	{
		history = new MarkovChainHistoryTableModel ();
		initComponents ();
		timer = null;
		transitionTextField = new JTextField [State.TransitionTo.values ().length];
		transitionTextField [0] = this.toS1TextField;
		transitionTextField [1] = this.toS2TextField;
		transitionTextField [2] = this.toS3TextField;
		transitionTextField [3] = this.toS4TextField;
		transitionTextField [4] = this.toS5TextField;
		transitionButton = new JButton [State.TransitionTo.values ().length];
		transitionButton [0] = this.S1Button;
		transitionButton [1] = this.S2Button;
		transitionButton [2] = this.S3Button;
		transitionButton [3] = this.S4Button;
		transitionButton [4] = this.S5Button;
	}
	/**
	 * This method is invoked when the parameters have changed.  In this case when this component receives a property change event from the component where the parameters are shown and edited by the user.
	 *
	 * <p> Several components shown in this form must be updated.
	 */
	private void parametersChanged ()
	{
		DataModel.parametersChanged ();
		this.history.fireTableStructureChanged ();
		this.updateTransitionProbabilities ();
		this.probabilityCombinationVectorHistoryComponent.parametersChanged ();
		this.markovChainHistoryComponent.parametersChanged ();
	}
	/**
	 * This method is invoked when a new transition of the partner selection must be performed.  This happens when the user presses the <i>next</i> button or when the thread launched when the user pressed the <i>run</i> button.
	 *
	 * <p> Several components shown in this form must be updated.
	 *
	 * @return {@code true} if a new transition was performed.  {@code false} means the markov chain is in an absorbing state.
	 */
	private boolean newTransition ()
	{
		boolean result = DataModel.newTransition ();
		this.history.fireTableDataChanged ();
		this.updateTransitionProbabilities ();
		this.probabilityCombinationVectorHistoryComponent.parametersChanged ();
		this.markovChainHistoryComponent.newTransition ();
		return result;
	}
	/**
	 * This method is invoked when a specific transition of the partner selection must be performed.  This happens when the user presses one of the five <i>Sx</i> buttons.
	 *
	 * <p> Several components shown in this form must be updated.
	 *
	 * @return {@code true} if a new transition was performed.  {@code false} means the markov chain is in an absorbing state.
	 */
	private boolean newTransition (State.TransitionTo t)
	{
		if (DataModel.newTransition (t)) {
			this.history.fireTableDataChanged ();
			this.updateTransitionProbabilities ();
			this.probabilityCombinationVectorHistoryComponent.parametersChanged ();
			this.markovChainHistoryComponent.newTransition ();
			return true;
		}
		else {
			return false;
		}
	}

	/**
	 * Update the transition probabilities from the current state of the partner selection model.
	 */
	private void updateTransitionProbabilities ()
	{
		for (State.TransitionTo s : State.TransitionTo.values ()) {
			this.transitionTextField [s.ordinal ()].setText (
				String.format ("%1.8f",
					DataModel.markovChain.getState ().probabilityTransitTo (s)));
		}
	}
	
	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
   // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
   private void initComponents() {
      javax.swing.JPanel controlPanel;
      javax.swing.JTabbedPane dataTabbedPane;
      java.awt.GridBagConstraints gridBagConstraints;
      javax.swing.JLabel jLabel10;
      javax.swing.JLabel jLabel5;
      javax.swing.JLabel jLabel6;
      javax.swing.JLabel jLabel7;
      javax.swing.JLabel jLabel8;
      javax.swing.JLabel jLabel9;
      javax.swing.JPanel jPanel2;
      javax.swing.JScrollPane jScrollPane1;
      javax.swing.JLabel messageLabel;
      javax.swing.JPanel transitionPanel;

      jPanel2 = new javax.swing.JPanel();
      transitionPanel = new javax.swing.JPanel();
      jLabel5 = new javax.swing.JLabel();
      jLabel6 = new javax.swing.JLabel();
      toS1TextField = new javax.swing.JTextField();
      jLabel7 = new javax.swing.JLabel();
      toS2TextField = new javax.swing.JTextField();
      jLabel8 = new javax.swing.JLabel();
      toS3TextField = new javax.swing.JTextField();
      jLabel9 = new javax.swing.JLabel();
      toS4TextField = new javax.swing.JTextField();
      jLabel10 = new javax.swing.JLabel();
      toS5TextField = new javax.swing.JTextField();
      markovChainHistoryComponent = new intopo.demonstrator.partnerselection.gui.MarkovChainHistoryComponent();
      markovChainParametersComponent = new intopo.demonstrator.partnerselection.gui.MarkovChainParametersForm();
      controlPanel = new javax.swing.JPanel();
      stopButton = new javax.swing.JButton();
      resetButton = new javax.swing.JButton();
      runButton = new javax.swing.JButton();
      nextButton = new javax.swing.JButton();
      messageLabel = new javax.swing.JLabel();
      S1Button = new javax.swing.JButton();
      S2Button = new javax.swing.JButton();
      S3Button = new javax.swing.JButton();
      S4Button = new javax.swing.JButton();
      S5Button = new javax.swing.JButton();
      dataTabbedPane = new javax.swing.JTabbedPane();
      probabilityCombinationVectorHistoryComponent = new intopo.demonstrator.partnerselection.gui.ProbabilityCombinationVectorHistoryComponent();
      jScrollPane1 = new javax.swing.JScrollPane();
      jTable1 = new javax.swing.JTable();

      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
      jPanel2.setLayout(new java.awt.GridBagLayout());

      transitionPanel.setLayout(new java.awt.GridBagLayout());

      transitionPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Transition Probabilities"));
      jLabel5.setText("from state S1 to state");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridwidth = 2;
      transitionPanel.add(jLabel5, gridBagConstraints);

      jLabel6.setText("S1");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 1;
      transitionPanel.add(jLabel6, gridBagConstraints);

      toS1TextField.setColumns(10);
      toS1TextField.setEditable(false);
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 1;
      transitionPanel.add(toS1TextField, gridBagConstraints);

      jLabel7.setText("S2");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 2;
      transitionPanel.add(jLabel7, gridBagConstraints);

      toS2TextField.setColumns(10);
      toS2TextField.setEditable(false);
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 2;
      transitionPanel.add(toS2TextField, gridBagConstraints);

      jLabel8.setText("S3");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 3;
      transitionPanel.add(jLabel8, gridBagConstraints);

      toS3TextField.setColumns(10);
      toS3TextField.setEditable(false);
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 3;
      transitionPanel.add(toS3TextField, gridBagConstraints);

      jLabel9.setText("S4");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 4;
      transitionPanel.add(jLabel9, gridBagConstraints);

      toS4TextField.setColumns(10);
      toS4TextField.setEditable(false);
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 4;
      transitionPanel.add(toS4TextField, gridBagConstraints);

      jLabel10.setText("S5");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 5;
      transitionPanel.add(jLabel10, gridBagConstraints);

      toS5TextField.setColumns(10);
      toS5TextField.setEditable(false);
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 5;
      transitionPanel.add(toS5TextField, gridBagConstraints);

      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 1;
      jPanel2.add(transitionPanel, gridBagConstraints);

      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.gridy = 2;
      jPanel2.add(markovChainHistoryComponent, gridBagConstraints);

      markovChainParametersComponent.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
         public void propertyChange(java.beans.PropertyChangeEvent evt) {
            propertyChanged(evt);
         }
      });

      jPanel2.add(markovChainParametersComponent, new java.awt.GridBagConstraints());

      getContentPane().add(jPanel2, java.awt.BorderLayout.WEST);

      stopButton.setText("Stop");
      stopButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            stopButtonActionPerformed(evt);
         }
      });

      controlPanel.add(stopButton);

      resetButton.setText("Reset");
      resetButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            resetButtonActionPerformed(evt);
         }
      });

      controlPanel.add(resetButton);

      runButton.setText("Run");
      runButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            runButtonActionPerformed(evt);
         }
      });

      controlPanel.add(runButton);

      nextButton.setText("Next");
      nextButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            nextButtonActionPerformed(evt);
         }
      });

      controlPanel.add(nextButton);

      messageLabel.setText("Transition");
      controlPanel.add(messageLabel);

      S1Button.setText("S1");
      S1Button.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            transitionButtonActionPerformed(evt);
         }
      });

      controlPanel.add(S1Button);

      S2Button.setText("S2");
      S2Button.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            transitionButtonActionPerformed(evt);
         }
      });

      controlPanel.add(S2Button);

      S3Button.setText("S3");
      S3Button.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            transitionButtonActionPerformed(evt);
         }
      });

      controlPanel.add(S3Button);

      S4Button.setText("S4");
      S4Button.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            transitionButtonActionPerformed(evt);
         }
      });

      controlPanel.add(S4Button);

      S5Button.setText("S5");
      S5Button.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            transitionButtonActionPerformed(evt);
         }
      });

      controlPanel.add(S5Button);

      getContentPane().add(controlPanel, java.awt.BorderLayout.SOUTH);

      dataTabbedPane.addTab("Plots", probabilityCombinationVectorHistoryComponent);

      jTable1.setModel(history);
      jScrollPane1.setViewportView(jTable1);

      dataTabbedPane.addTab("Raw Data", jScrollPane1);

      getContentPane().add(dataTabbedPane, java.awt.BorderLayout.CENTER);

      pack();
   }// </editor-fold>//GEN-END:initComponents

	private void stopButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
		this.timer.cancel ();
		this.timer = null;
		this.stopButton.setEnabled (false);
		this.runButton.setEnabled (true);
		this.nextButton.setEnabled (true);
		this.resetButton.setEnabled (true);
	}//GEN-LAST:event_stopButtonActionPerformed

	private void runButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runButtonActionPerformed
		this.timer = new Timer ();
		this.timer.schedule (new Walk (), 0, 70);
		this.stopButton.setEnabled (true);
		this.runButton.setEnabled (false);
		this.nextButton.setEnabled (false);
		this.resetButton.setEnabled (false);
	}//GEN-LAST:event_runButtonActionPerformed

	private void propertyChanged (java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_propertyChanged
		if (evt.getPropertyName ().equals ("parameters")) {
			this.parametersChanged ();
		}
	}//GEN-LAST:event_propertyChanged

	private void resetButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetButtonActionPerformed
		this.parametersChanged ();
	}//GEN-LAST:event_resetButtonActionPerformed

	private void transitionButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_transitionButtonActionPerformed
		for (State.TransitionTo t : State.TransitionTo.values ()) {
			if (transitionButton [t.ordinal ()] == evt.getSource ()) {
				newTransition (t);
				return ;
			}
		}
	}//GEN-LAST:event_transitionButtonActionPerformed

	private void nextButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextButtonActionPerformed
		this.newTransition ();
	}//GEN-LAST:event_nextButtonActionPerformed
	
	/**
	 * Entry point of the demonstrator of the partner selection model.
	 *
	 * @param args the command line arguments
	 */
	public static void main (String args[])
	{
		java.awt.EventQueue.invokeLater (new Runnable () {
			public void run () {
				new MonteCarloForm ().setVisible (true);
			}
		});
	}
	
   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JButton S1Button;
   private javax.swing.JButton S2Button;
   private javax.swing.JButton S3Button;
   private javax.swing.JButton S4Button;
   private javax.swing.JButton S5Button;
   private javax.swing.JTable jTable1;
   private intopo.demonstrator.partnerselection.gui.MarkovChainHistoryComponent markovChainHistoryComponent;
   private intopo.demonstrator.partnerselection.gui.MarkovChainParametersForm markovChainParametersComponent;
   private javax.swing.JButton nextButton;
   private intopo.demonstrator.partnerselection.gui.ProbabilityCombinationVectorHistoryComponent probabilityCombinationVectorHistoryComponent;
   private javax.swing.JButton resetButton;
   private javax.swing.JButton runButton;
   private javax.swing.JButton stopButton;
   private javax.swing.JTextField toS1TextField;
   private javax.swing.JTextField toS2TextField;
   private javax.swing.JTextField toS3TextField;
   private javax.swing.JTextField toS4TextField;
   private javax.swing.JTextField toS5TextField;
   // End of variables declaration//GEN-END:variables

	/**
	 * This class is responsible for running the partner classification model.
	 */
	final class Walk
		extends java.util.TimerTask
	{
		public void run ()
		{
			if (!newTransition ()) {
				timer.cancel ();
			}
		}
	}
}

/**
 * This class provides the raw data about the current run of the Markov Chain
 */
class MarkovChainHistoryTableModel
	extends javax.swing.table.AbstractTableModel
{
	public String getColumnName (int index)
	{
		if (index < DataModel.parameters.getPoolSize ()) {
			return String.format ("p%d", index);
		}
		else {
			return String.format ("c%d", index - DataModel.parameters.getPoolSize ());
		}
	}
	public int getColumnCount ()
	{
		return 2 * DataModel.parameters.getPoolSize ();
	}
	public int getRowCount ()
	{
		return DataModel.history.size ();
	}
	public Object getValueAt (int row, int column)
	{
		try {
			if (column < DataModel.parameters.getPoolSize ()) {
				return Integer.toString (DataModel.history.get (row).getRawProbability (column));
			}
			else {
				if (DataModel.history.get (row).isAcceptable (column - DataModel.parameters.getPoolSize ()))
					return "X";
				else
					return "-";
			}
		}
		catch (Exception e) {
			return column + "," + row;
		}
	}
	public Class<?> getColumnClass (int column)
	{
		if (column < DataModel.parameters.getPoolSize ()) {
			return Integer.class;
		}
		else {
			return String.class;
		}
	}
}
